package com.xr.system.common.base;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

public class MyPage<T> implements IPage<T> {

	private static final long serialVersionUID = -8447987374288843989L;

	/**
	 * 查询数据列表
	 */
	protected List<T> records = Collections.emptyList();

	@Getter
	private long next;

	@Getter
	private long prev;

	public void setAscOrder(String... ascOrder) {
		for (String s : ascOrder) {
			orders.add(OrderItem.asc(s));
		}
	}

	public void setDescOrder(String... descOrder) {
		for (String s : descOrder) {
			orders.add(OrderItem.desc(s));
		}
	}

	/**
	 * 总数
	 */
	protected long total = 0;

	/**
	 * 每页显示条数
	 */
	protected long size = 10;

	/**
	 * 当前页
	 */
	protected long current = 1;

	/**
	 * 排序字段信息
	 */
	@Setter
	@JsonProperty(access = Access.WRITE_ONLY)
	protected List<OrderItem> orders = new ArrayList<>();

	/**
	 * 自动优化 COUNT SQL
	 */
	@JsonProperty(access = Access.WRITE_ONLY)
	protected boolean optimizeCountSql = true;

	/**
	 * 是否进行 count 查询
	 */
	@JsonProperty(access = Access.WRITE_ONLY)
	protected boolean searchCount = true;

	/**
	 * optimizeJoinOfCountSql
	 */
	@Setter
	protected boolean optimizeJoinOfCountSql = true;

	/**
	 * countId
	 */
	@Setter
	@JsonProperty(access = Access.WRITE_ONLY)
	protected String countId;

	/**
	 * maxLimit
	 */
	@Setter
	@JsonProperty(access = Access.WRITE_ONLY)
	protected Long maxLimit;

	public MyPage() {

	}

	/**
	 * 分页构造函数
	 * @param current 当前页
	 * @param size 每页显示条数
	 */
	public MyPage(long current, long size) {
		this(current, size, 0);
	}

	public MyPage(long current, long size, long total) {
		this(current, size, total, true);
	}

	public MyPage(long current, long size, boolean searchCount) {
		this(current, size, 0, searchCount);
	}

	public MyPage(long current, long size, long total, boolean searchCount) {
		if (current > 1) {
			this.current = current;
		}
		this.size = size;
		this.total = total;
		this.searchCount = searchCount;
	}

	/**
	 * 是否存在上一页
	 * @return true / false
	 */
	public boolean hasPrevious() {
		return current > 1;
	}

	/**
	 * 是否存在下一页
	 * @return true / false
	 */
	public boolean hasNext() {
		return current < getPages();
	}

	@Override
	public List<T> getRecords() {
		return records;
	}

	@Override
	public MyPage<T> setRecords(List<T> records) {
		this.records = records;
		return this;
	}

	@Override
	public long getTotal() {
		return total;
	}

	@Override
	public MyPage<T> setTotal(long total) {
		this.total = total;
		next = hasNext() ? current + 1 : -1;
		prev = hasPrevious() ? current - 1 : -1;
		return this;
	}

	@Override
	public long getSize() {
		return size;
	}

	@Override
	public MyPage<T> setSize(long size) {
		this.size = size;
		return this;
	}

	@Override
	public long getCurrent() {
		return current;
	}

	@Override
	public MyPage<T> setCurrent(long current) {
		this.current = current;
		return this;
	}

	@Override
	public String countId() {
		return countId;
	}

	@Override
	public Long maxLimit() {
		return maxLimit;
	}

	/**
	 * 查找 order 中正序排序的字段数组
	 * @param filter 过滤器
	 * @return 返回正序排列的字段数组
	 */
	private String[] mapOrderToArray(Predicate<OrderItem> filter) {
		List<String> columns = new ArrayList<>(orders.size());
		orders.forEach(i -> {
			if (filter.test(i)) {
				columns.add(i.getColumn());
			}
		});
		return columns.toArray(new String[0]);
	}

	/**
	 * 移除符合条件的条件
	 * @param filter 条件判断
	 */
	private void removeOrder(Predicate<OrderItem> filter) {
		for (int i = orders.size() - 1; i >= 0; i--) {
			if (filter.test(orders.get(i))) {
				orders.remove(i);
			}
		}
	}

	/**
	 * 添加新的排序条件，构造条件可以使用工厂
	 * @param items 条件
	 * @return 返回分页参数本身
	 */
	public MyPage<T> addOrder(OrderItem... items) {
		orders.addAll(Arrays.asList(items));
		return this;
	}

	/**
	 * 添加新的排序条件，构造条件可以使用工厂
	 * @param items 条件
	 * @return 返回分页参数本身
	 */
	public MyPage<T> addOrder(List<OrderItem> items) {
		orders.addAll(items);
		return this;
	}

	@Override
	public List<OrderItem> orders() {
		return orders;
	}

	@Override
	public boolean optimizeCountSql() {
		return optimizeCountSql;
	}

	public static <T> MyPage<T> of(long current, long size, long total, boolean searchCount) {
		return new MyPage<>(current, size, total, searchCount);
	}

	@Override
	public boolean optimizeJoinOfCountSql() {
		return optimizeJoinOfCountSql;
	}

	public MyPage<T> setSearchCount(boolean searchCount) {
		this.searchCount = searchCount;
		return this;
	}

	public MyPage<T> setOptimizeCountSql(boolean optimizeCountSql) {
		this.optimizeCountSql = optimizeCountSql;
		return this;
	}

	@Override
	public long getPages() {
		return IPage.super.getPages();
	}

	/* ---------------- 以下为静态构造方式 ---------------- */
	public static <T> MyPage<T> of(long current, long size) {
		return of(current, size, 0);
	}

	public static <T> MyPage<T> of(long current, long size, long total) {
		return of(current, size, total, true);
	}

	public static <T> MyPage<T> of(long current, long size, boolean searchCount) {
		return of(current, size, 0, searchCount);
	}

	@Override
	public boolean searchCount() {
		if (total < 0) {
			return false;
		}
		return searchCount;
	}

	/**
	 * begin---------------- 未来抛弃移除的方法 ---------------- 该部分属性转移至 {@link PageDTO}
	 */
	@Deprecated
	public String getCountId() {
		return countId;
	}

	@Deprecated
	public Long getMaxLimit() {
		return maxLimit;
	}

	@Deprecated
	public List<OrderItem> getOrders() {
		return orders;
	}

	@Deprecated
	public boolean isOptimizeCountSql() {
		return optimizeCountSql;
	}

	@Deprecated
	public boolean isSearchCount() {
		return searchCount;
	}
	/**
	 * end---------------- 未来抛弃移除的方法 ---------------- 该部分属性转移至 {@link PageDTO}
	 */

}
